# Rsbuild Core

本章节描述了 Rsbuild 提供的一些核心方法。

## createRsbuild

创建一个 [Rsbuild 实例对象](/api/javascript-api/instance)。

- **类型：**

```ts
function createRsbuild(
  options?: CreateRsbuildOptions,
): Promise<RsbuildInstance>;
```

- **示例：**

```ts
import { createRsbuild } from '@rsbuild/core';

const rsbuild = await createRsbuild({
  rsbuildConfig: {
    // rsbuild configs
  },
});
```

### options

`createRsbuild` 的第一个参数是一个配置对象，你可以传入以下选项：

```ts
type CreateRsbuildOptions = {
  cwd?: string;
  rsbuildConfig?: RsbuildConfig;
};
```

各个选项的作用：

- `cwd`：当前执行构建的根路径，默认值为 `process.cwd()`
- `rsbuildConfig`：Rsbuild 配置对象。Rsbuild 提供了丰富的配置项，允许你对构建行为进行灵活定制，你可以在[配置](/config/)中找到所有可用的配置项。

## loadConfig

加载 Rsbuild 配置文件。

- **类型：**

```ts
function loadConfig(params?: {
  // 默认为 process.cwd()
  cwd?: string;
  // 指定配置文件路径，可以为相对路径或绝对路径
  path?: string;
}): Promise<{
  content: RsbuildConfig;
  filePath: string | null;
}>;
```

- **示例：**

```ts
import { loadConfig } from '@rsbuild/core';

const { content } = await loadConfig();

console.log(content); // -> Rsbuild config object

const rsbuild = await createRsbuild({
  rsbuildConfig: content,
});
```

如果 cwd 目录下不存在 Rsbuild 配置文件，loadConfig 方法的返回值为 `{ content: {}, filePath: null }`。

## loadEnv

加载 `.env` 文件，并返回所有以 prefixes 开头的环境变量。

- **类型：**

```ts
type LoadEnvOptions = {
  /**
   * 加载 env 文件的根路径
   * @default process.cwd()
   */
  cwd?: string;
  /**
   * 用于指定 .env.[mode] 文件的名称
   * 等价于 Rsbuild CLI 的 `--env-mode` 选项
   * @default process.env.NODE_ENV
   */
  mode?: string;
  /**
   * public 变量的前缀
   * @default ['PUBLIC_']
   */
  prefixes?: string[];
};

function loadEnv(options: LoadEnvOptions): {
  /** .env 文件包含的所有环境变量 */
  parsed: Record<string, string>;
  /** 所有 env 文件的绝对路径 */
  filePaths: string[];
  /** 以 prefixes 开头的环境变量 */
  publicVars: Record<string, string>;
  /** 从 `process.env` 上清除挂载的环境变量 */
  cleanup: () => void;
};
```

- **示例：**

```ts
import { loadEnv, mergeRsbuildConfig } from '@rsbuild/core';

const { parsed, publicVars } = loadEnv();

const mergedConfig = mergeRsbuildConfig(
  {
    source: {
      define: publicVars,
    },
  },
  userConfig,
);
```

该方法也会加载 `.env.local` 和 `.env.[mode]` 等文件，详见 [环境变量](/guide/advanced/env-vars)。

:::tip
Rsbuild CLI 会自动调用 `loadEnv()` 方法，如果你在使用 Rsbuild CLI，可以通过 [--env-mode](/guide/advanced/env-vars#env-模式) 选项来设置 `mode` 参数。
:::

## mergeRsbuildConfig

用于合并多份 Rsbuild 配置对象。

`mergeRsbuildConfig` 函数接收多个配置对象作为参数，它会将每一个配置对象进行深层合并，自动将多个函数项合并为顺序执行的函数数组，返回一个合并后的配置对象。

- **类型：**

```ts
function mergeRsbuildConfig(...configs: RsbuildConfig[]): RsbuildConfig;
```

### 基础示例

```ts
import { mergeRsbuildConfig } from '@rsbuild/core';

const config1 = {
  dev: {
    https: false,
  },
};
const config2 = {
  dev: {
    https: true,
  },
};

const mergedConfig = mergeRsbuildConfig(config1, config2);

console.log(mergedConfig); // { dev: { https: true } }
```

> 该方法不会修改入参中的 config 对象。

### 合并规则

除了深层合并外，`mergeRsbuildConfig` 函数还会对部分选项进行特殊处理。

比如 [tools.rspack](/config/tools/rspack) 可以被设置为一个函数，当多份配置对象都包含 `tools.rspack` 时，`mergeRsbuildConfig` 不会简单地保留最后一个函数。相反，它会将所有的 `tools.rspack` 函数或对象合并到一个数组中。

```ts
import { mergeRsbuildConfig } from '@rsbuild/core';

const config1 = {
  tools: {
    rspack: {
      someOption: true,
    },
  },
};
const config2 = {
  tools: {
    rspack: (config) => {
      console.log('function 1');
      return config;
    },
  },
};
const config3 = {
  tools: {
    rspack: (config) => {
      console.log('function 2');
      return config;
    },
  },
};

const mergedConfig = mergeRsbuildConfig(config1, config2, config3);
```

在以上示例中，合并后的配置为以下形式，该数组首先包含了一个对象 `{ someOption: true }`，然后是按合并顺序排列的两个函数。

数组中的每一项会依次执行，并且上一个函数的输出将作为下一个函数的输入，最终生成一份 Rspack 配置。

```ts
const mergedConfig = {
  tools: {
    rspack: [
      {
        someOption: true,
      },
      (config) => {
        console.log('function 1');
        return config;
      },
      (config) => {
        console.log('function 2');
        return config;
      },
    ],
  },
};
```

通过这种方法，我们可以确保合并多份配置对象时，相同的多个 `tools.rspack` 字段均能够生效。

在 Rsbuild 中，大部分支持函数值的选项都使用上述规则，比如 `tools.postcss`、`tools.less`、`tools.bundlerChain` 等。

## logger

用于输出格式统一的日志信息，基于 [rslog](https://github.com/rspack-contrib/rslog)。

- **示例：**

```ts
import { logger } from '@rsbuild/core';

// A gradient welcome log
logger.greet(`\n➜ Rsbuild v1.0.0\n`);

// Info
logger.info('This is a info message');

// Start
logger.start('This is a start message');

// Warn
logger.warn('This is a warn message');

// Ready
logger.ready('This is a ready message');

// Success
logger.success('This is a success message');

// Error
logger.error('This is a error message');
logger.error(new Error('This is a error message with stack'));

// Debug
logger.debug('This is a debug message');

// Same as console.log
logger.log('This is a log message');
```

### 自定义 Logger

你可以使用 `logger.override` 方法来覆盖默认 logger 的部分或全部方法：

```ts
import { logger } from '@rsbuild/core';

logger.override({
  log: (message) => {
    console.log(`[log] ${message}`);
  },
  info: (message) => {
    console.log(`[info] ${message}`);
  },
  warn: (message) => {
    console.warn(`[warn] ${message}`);
  },
  start: (message) => {
    console.log(`[start] ${message}`);
  },
  ready: (message) => {
    console.log(`[ready] ${message}`);
  },
  error: (message) => {
    console.error(`[error] ${message}`);
  },
  success: (message) => {
    console.error(`[success] ${message}`);
  },
  debug: (message) => {
    if (process.env.DEBUG) {
      console.log(`[debug] ${message}`);
    }
  },
});

logger.info('hello'); // [info] hello
```

## rspack

由 `@rspack/core` 导出的 `rspack` 对象。

你可以直接从 `@rsbuild/core` 中引用 `rspack` 对象，而无须额外安装 `@rspack/core` 依赖。

- **类型：** `Rspack`
- **示例：**

```ts
import { rspack } from '@rsbuild/core';

console.log(rspack.rspackVersion); // 1.0.0
console.log(rspack.util.createHash);
```

> 请参考 [Rspack - JavaScript API](https://rspack.dev/api/javascript-api) 了解更多。

## version

当前使用的 `@rsbuild/core` 的版本。

- **类型：** `string`
- **示例：**

```ts
import { version } from '@rsbuild/core';

console.log(version); // 1.0.0
```

## ensureAssetPrefix

`ensureAssetPrefix` 函数用于将给定的 `assetPrefix` 拼接到一个可能是 URL 的字符串前面。如果传入的字符串已经是一个完整的 URL，则直接返回该字符串。

- **类型：**

```ts
function ensureAssetPrefix(
  // 需要处理的 URL 字符串。可以是相对路径或绝对 URL
  url: string,
  // 需要拼接的 URL 前缀
  assetPrefix: string
) => string;
```

- **示例：**

```ts
import { ensureAssetPrefix } from '@rsbuild/core';

ensureAssetPrefix('foo/bar.js', '/static/');
// -> '/static/foo/bar.js'

ensureAssetPrefix('foo/bar.js', 'https://example.com/static/');
// -> 'https://example.com/static/foo/bar.js'

ensureAssetPrefix(
  'https://example.com/index.html',
  'https://example.com/static/',
);
// -> 'https://example.com/index.html'
```

## reduceConfigs

`reduceConfigs` 函数将一个或多个配置对象合并为最终配置，它还允许通过函数修改配置对象。

- **版本：** `>= 1.0.0`
- **类型：**

```ts
type OneOrMany<T> = T | T[];
type ConfigChain<T> = OneOrMany<T | ((config: T) => T | void)>;

function reduceConfigs<T>(options: {
  /**
   * 初始配置对象
   */
  initial: T;
  /**
   * 要合并到初始配置中的配置对象、函数，或是由配置对象和函数组成的数组
   */
  config?: ConfigChain<T> | undefined;
  /**
   * 合并配置对象的函数
   * @default Object.assign
   */
  mergeFn?: typeof Object.assign;
}): T;
```

- **示例：**

```ts
import { reduceConfigs } from '@rsbuild/core';

const initial = { a: 1, b: 2 };

// 合并一个对象
const finalConfig1 = reduceConfigs({
  initial,
  config: { b: 3, c: 4 },
});
// -> { a: 1, b: 3, c: 4 }

// 使用一个函数修改配置
const finalConfig2 = reduceConfigs({
  initial,
  config: (config) => ({ ...config, b: 5, d: 6 }),
});
// -> { a: 1, b: 5, d: 6 }

// 合并一个对象/函数数组
const finalConfig3 = reduceConfigs({
  initial,
  config: [
    { b: 7 },
    (config) => ({ ...config, c: 8 }),
    (config) => ({ ...config, d: 9 }),
  ],
});
// -> { a: 1, b: 7, c: 8, d: 9 }
```

## reduceConfigsWithContext

`reduceConfigsWithContext` 函数的作用与 `reduceConfigs` 相似，它允许你额外传入一个 `context` 对象给配置函数。

- **版本：** `>= 1.0.0`
- **类型：**

```ts
type OneOrMany<T> = T | T[];
type ConfigChainWithContext<T, Ctx> = OneOrMany<
  T | ((config: T, ctx: Ctx) => T | void)
>;

function reduceConfigsWithContext<T, Ctx>(options: {
  /**
   * 初始配置对象
   */
  initial: T;
  /**
   * 要合并到初始配置中的配置对象、函数，或是由配置对象和函数组成的数组
   */
  config?: ConfigChainWithContext<T> | undefined;
  /**
   * 可以在配置函数中使用的上下文对象。
   */
  ctx?: Ctx;
  /**
   * 合并配置对象的函数
   * @default Object.assign
   */
  mergeFn?: typeof Object.assign;
}): T;
```

- **示例：**

```ts
import { reduceConfigsWithContext } from '@rsbuild/core';

const initial = { a: 1, b: 2 };
const context = { user: 'admin' };

const finalConfig = reduceConfigsWithContext({
  initial,
  config: [
    { b: 3 },
    (config, ctx) => ({ ...config, c: ctx.user === 'admin' ? 99 : 4 }),
  ],
  ctx: context,
});
// -> { a: 1, b: 3, c: 99 }
```
